import os
import subprocess
import time
import zipfile
from pathlib import Path


class MavenLocalInstaller:
    def __init__(self, local_repo_path=None):
        """
        初始化Maven本地仓库安装器

        Args:
            local_repo_path: 本地仓库路径，默认为 ~/.m2/repository
        """
        if local_repo_path is None:
            self.local_repo = Path.home() / '.m2' / 'repository'
        else:
            self.local_repo = Path(local_repo_path)

        # 确保本地仓库目录存在
        self.local_repo.mkdir(parents=True, exist_ok=True)
        self.mvn_cmd = self._find_mvn_command()

    def _find_mvn_command(self):
        """
        查找mvn命令的完整路径

        Returns:
            str: mvn命令路径，如果找不到则返回None
        """
        # 常见的Maven安装路径
        possible_paths = [
            'mvn',  # 系统PATH中的mvn
            'mvn.cmd',  # Windows下的mvn.cmd
            os.path.expanduser('~/.m2/bin/mvn'),  # 用户目录下的Maven
        ]

        # 检查MAVEN_HOME环境变量
        maven_home = os.environ.get('MAVEN_HOME') or os.environ.get('M2_HOME')
        if maven_home:
            mvn_path = os.path.join(maven_home, 'bin', 'mvn.cmd' if os.name == 'nt' else 'mvn')
            possible_paths.insert(0, mvn_path)

        for cmd in possible_paths:
            try:
                subprocess.run([cmd, '--version'], capture_output=True, check=True)
                return cmd
            except (subprocess.CalledProcessError, FileNotFoundError):
                continue

        print("错误: 找不到mvn命令，请确保Maven已正确安装")
        print("请设置MAVEN_HOME环境变量或将其添加到系统PATH中")
        return None

    def install_from_directory(self, root_dir):
        """
        扫描目录并自动安装其中的JAR和POM文件到本地仓库

        整体流程逻辑：
        1. 遍历目录，找到没有子目录的叶子目录（版本目录）
        2. 检查版本目录中是否存在JAR和POM文件
        3. 根据文件存在情况决定安装策略：
           - 同时存在JAR和POM：安装JAR文件并关联POM
           - 仅存在JAR：安装JAR文件
           - 仅存在POM：安装POM文件
           - 都不存在：跳过

        Args:
            root_dir: 要扫描的根目录路径
        """
        root_path = Path(root_dir)
        if not root_path.exists():
            print(f"目录 {root_dir} 不存在")
            return False

        installed_count = 0
        failed_count = 0
        skip_count = 0
        # 找到所有没有子目录的叶子目录（版本目录）
        version_dirs = self._find_version_directories(root_path)
        print(f"找到 {len(version_dirs)} 个版本目录")
        start_time = time.time()
        for version_dir in version_dirs:
            print(f"\n处理版本目录: {version_dir}")
            try:
                # 从目录结构解析坐标
                group_id, artifact_id, version = self._parse_coordinates_from_directory(version_dir, root_path)

                if not all([group_id, artifact_id, version]):
                    print(f"  无法从目录结构解析Maven坐标，跳过")
                    continue

                print(f"  坐标: {group_id}:{artifact_id}:{version}")

                # 查找该目录下的JAR和POM文件
                jar_files = list(version_dir.glob("*.jar"))
                pom_files = list(version_dir.glob("*.pom")) + list(version_dir.glob("pom.xml"))

                # 根据文件存在情况决定安装策略
                if jar_files and (pom_files or True):  # 优先安装JAR文件
                    jar_file = jar_files[0]  # 取第一个JAR文件
                    pom_file = pom_files[0] if pom_files else None

                    print(f"  安装JAR文件: {jar_file.name}")
                    if self.install_from_file(str(jar_file), group_id, artifact_id, version, 'jar', pom_file):
                        installed_count += 1
                    else:
                        failed_count += 1

                elif pom_files:  # 仅存在POM文件
                    pom_file = pom_files[0]  # 取第一个POM文件

                    print(f"  安装POM文件: {pom_file.name}")
                    if self.install_from_file(str(pom_file), group_id, artifact_id, version, 'pom'):
                        installed_count += 1
                    else:
                        failed_count += 1
                else:
                    skip_count+=1
                    print(f"  目录中没有可安装的文件，跳过")

            except Exception as e:
                print(f"  处理目录 {version_dir} 时出错: {e}")
                failed_count += 1

        print(f"\n安装完成: 成功 {installed_count} 个, 失败 {failed_count} 个, 跳过 {skip_count} 个")
        # 给出总的耗时时长
        print(f"耗时: {round(time.time() - start_time, 2)} 秒")
        return failed_count == 0

    def _find_version_directories(self, root_path):
        """
        找到所有没有子目录的叶子目录（版本目录）

        Args:
            root_path: 根目录路径

        Returns:
            list: 版本目录路径列表
        """
        version_dirs = []

        # 递归遍历所有目录
        for dir_path in root_path.rglob("*"):
            if dir_path.is_dir():
                # 检查该目录是否有子目录
                has_subdirs = any(child.is_dir() for child in dir_path.iterdir()) if dir_path.exists() else False

                # 如果没有子目录，则为版本目录
                if not has_subdirs:
                    version_dirs.append(dir_path)

        return version_dirs

    def _parse_coordinates_from_directory(self, version_dir, root_path):
        """
        从版本目录路径解析Maven坐标

        根据Maven仓库目录结构：root_dir/group_id/artifact_id/version/

        Args:
            version_dir: 版本目录路径
            root_path: 根目录路径

        Returns:
            tuple: (group_id, artifact_id, version)
        """
        try:
            # 计算相对于根目录的路径
            try:
                relative_path = version_dir.relative_to(root_path)
            except ValueError:
                # 如果无法计算相对路径，使用绝对路径
                relative_path = version_dir

            # 确保路径至少有3层（group_id/artifact_id/version）
            if len(relative_path.parts) >= 3:
                # 从路径中提取坐标信息
                version = relative_path.parts[-1]  # 最后一层是version
                artifact_id = relative_path.parts[-2]  # 倒数第二层是artifact_id
                group_parts = relative_path.parts[:-2]  # 其余部分是group_id路径
                group_id = '.'.join(group_parts)  # 用点号连接group_id路径

                return group_id, artifact_id, version

            return None, None, None
        except Exception as e:
            print(f"  从目录解析坐标时出错: {e}")
            return None, None, None

    def install_from_file(self, file_path, group_id, artifact_id, version,
                          packaging='jar', pom_file=None):
        """
        使用mvn install:install-file命令从本地文件安装到本地仓库

        Args:
            file_path: 要安装的文件路径
            group_id: Group ID
            artifact_id: Artifact ID
            version: 版本号
            packaging: 打包类型
            pom_file: POM文件路径（可选）
        """
        try:
            # 使用双反斜杠转义路径
            file_path_escaped = str(file_path).replace('\\', '\\\\')

            cmd = [
                self.mvn_cmd, 'install:install-file',
                f'-Dfile={file_path_escaped}',
                f'-DgroupId={group_id}',
                f'-DartifactId={artifact_id}',
                f'-Dversion={version}',
                f'-Dpackaging={packaging}'
            ]

            if pom_file:
                pom_file_escaped = str(pom_file).replace('\\', '\\\\')
                cmd.append(f'-DpomFile={pom_file_escaped}')

            print(f"  执行命令: {' '.join(cmd)}")
            result = subprocess.run(cmd, capture_output=True, text=True)

            if result.returncode == 0:
                print(f"  成功安装 {group_id}:{artifact_id}:{version}")
                # 把cmd 追加写入到当前目录下import_jar_pom.cmd
                self.save_string_to_file(' '.join(cmd), 'import_jar_pom.cmd')
                return True
            else:
                print(f"  安装失败: {result.stderr}")
                return False

        except Exception as e:
            print(f"  安装过程中出错: {str(e)}")
            return False

    def save_string_to_file(self, cmd, filename):
        """
        将字符串追加写入到文件中

        Args:
            content: 要写入的内容
            filename: 文件名
        """
        try:

            # 以追加模式写入文件，每个命令占一行
            with open(filename, 'a', encoding='utf-8') as f:
                f.write(cmd + '\n')
        except Exception as e:
            print(f"写入文件 {filename} 时出错: {str(e)}")
    def _extract_maven_coordinates_from_jar(self, jar_path):
        """
        从JAR文件的META-INF/maven目录中提取Maven坐标

        Args:
            jar_path: JAR文件路径

        Returns:
            tuple: (group_id, artifact_id, version) 或 (None, None, None)
        """
        try:
            with zipfile.ZipFile(jar_path, 'r') as jar:
                # 查找META-INF/maven目录下的pom.properties文件
                for file_info in jar.filelist:
                    if (file_info.filename.startswith('META-INF/maven/') and
                            file_info.filename.endswith('/pom.properties')):

                        with jar.open(file_info) as prop_file:
                            content = prop_file.read().decode('utf-8')
                            properties = {}
                            for line in content.splitlines():
                                if '=' in line and not line.startswith('#'):
                                    key, value = line.split('=', 1)
                                    properties[key.strip()] = value.strip()

                            group_id = properties.get('groupId')
                            artifact_id = properties.get('artifactId')
                            version = properties.get('version')

                            if all([group_id, artifact_id, version]):
                                return group_id, artifact_id, version
            return None, None, None
        except Exception as e:
            print(f"  从JAR提取坐标时出错: {e}")
            return None, None, None

    def _parse_coordinates_from_filepath(self, file_path, root_path):
        """
        从文件路径解析Maven坐标

        根据Maven仓库目录结构：root_dir/group_id/artifact_id/version/filename

        Args:
            file_path: 文件路径
            root_path: 根目录路径

        Returns:
            tuple: (group_id, artifact_id, version)
        """
        try:
            file_path_obj = Path(file_path)
            root_path_obj = Path(root_path)

            # 计算相对于根目录的路径
            try:
                relative_path = file_path_obj.relative_to(root_path_obj)
            except ValueError:
                # 如果无法计算相对路径，回退到绝对路径处理
                relative_path = file_path_obj

            # 确保路径至少有3层（group_id/artifact_id/version）
            if len(relative_path.parts) >= 3:
                # 从路径中提取坐标信息
                # 最后一层是文件名，倒数第一层是version，倒数第二层是artifact_id
                version = relative_path.parts[-2]  # 倒数第二层
                artifact_id = relative_path.parts[-3]  # 倒数第三层

                # 前面的所有部分组成group_id
                if len(relative_path.parts) > 3:
                    group_parts = relative_path.parts[:-3]  # 除了最后三层之外的部分
                    group_id = '.'.join(group_parts)
                    return group_id, artifact_id, version

            return None, None, None
        except Exception as e:
            print(f"  从路径解析坐标时出错: {e}")
            return None, None, None

    def _find_pom_for_jar(self, jar_path):
        """
        查找与JAR文件对应的POM文件

        Args:
            jar_path: JAR文件路径

        Returns:
            str or None: POM文件路径
        """
        # 同目录下的同名POM文件
        pom_path = jar_path.with_suffix('.pom')
        if pom_path.exists():
            return str(pom_path)

        # pom.xml文件
        pom_xml_path = jar_path.parent / 'pom.xml'
        if pom_xml_path.exists():
            return str(pom_xml_path)

        # JAR包内的POM文件
        try:
            with zipfile.ZipFile(jar_path, 'r') as jar:
                for file_info in jar.filelist:
                    if file_info.filename.endswith('.pom') or file_info.filename.endswith('/pom.xml'):
                        # 如果JAR内有POM文件，可以考虑提取出来使用
                        pass
        except:
            pass

        return None

def main():
    """
    主函数示例
    """
    installer = MavenLocalInstaller(local_repo_path='E:\\m2')

    # 示例1: 从远程仓库安装
    # installer.install_from_remote_repo(
    #     group_id='org.apache.commons',
    #     artifact_id='commons-lang3',
    #     version='3.12.0',
    #     remote_repo_url='https://repo1.maven.org/maven2/'
    # )

    # 示例2: 从本地文件安装
    installer.install_from_directory('E:\\aad\\test')

    # 示例3: 从POM文件安装
    # installer.install_from_pom('/path/to/pom.xml')


if __name__ == "__main__":
    main()
